# 随机森林分类
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
from sklearn.metrics import classification_report
import numpy as np

plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False

# 加载数据
df = pd.read_csv('resampled_data_g1.csv')

# 分离特征和标签
X = df.drop('Air Quality', axis=1)
y = df['Air Quality']

# 将分类标签转换为数值
y_numeric = pd.Categorical(y).codes

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y_numeric, test_size=0.2)

# 使用随机森林分类器
rf = RandomForestClassifier()

rf.fit(X_train, y_train)


# 在测试集上评估模型
y_pred = rf.predict(X_test)

# 准确率、精确率、召回率、F1分数
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred, average='macro')
recall = recall_score(y_test, y_pred, average='macro')
f1 = f1_score(y_test, y_pred, average='macro')

print(f"准确率: {accuracy}")
print(f"精确率: {precision}")
print(f"召回率: {recall}")
print(f"F1分数: {f1}")


# 绘制混淆矩阵
conf_mat = confusion_matrix(y_test, y_pred)
disp = ConfusionMatrixDisplay(confusion_matrix=conf_mat, display_labels=np.unique(y_numeric))
disp.plot()
plt.title("混淆矩阵")
plt.show()


# 创建从数字标签到类别名称的映射
label_names = df['Air Quality'].astype('category').cat.categories.tolist()
label_to_name = dict(enumerate(label_names))

# 确保y_test和y_pred都是基于原始的类别名称
y_test_names = pd.Series(y_test).map(label_to_name)
y_pred_names = pd.Series(y_pred).map(label_to_name)

# 打印分类报告，包括每一类的精确率、召回率、F1分数和支持度
report = classification_report(y_test_names, y_pred_names, target_names=label_names, zero_division=0)
print("分类报告:\n", report)

# 如果需要单独访问这些值，可以这样做：
report_dict = classification_report(y_test_names, y_pred_names, output_dict=True, target_names=label_names, zero_division=0)
for label in label_names:
    metrics = report_dict[label]
    print(f"对于类别 {label}:")
    print(f"  精确率: {metrics['precision']:.2f}")
    print(f"  召回率: {metrics['recall']:.2f}")
    print(f"  F1分数: {metrics['f1-score']:.2f}")
    print(f"  支持度: {metrics['support']}")


# 获取特征重要性
feature_importances = rf.feature_importances_

# 打印特征重要性
print("特征重要性:")
for feature, importance in zip(X.columns, feature_importances):
    print(f"{feature}: {importance:.4f}")

# 可视化特征重要性
plt.figure(figsize=(10, 8))
plt.barh(X.columns, feature_importances, color='b')
plt.xlabel('特征重要性')
plt.title('特征重要性可视化')
plt.gca().invert_yaxis()  # 反转y轴，使得最重要的特征在上方
plt.show()